#ifndef string_h
#define string_h

// this header needs (all known encodings from wchar)
#include "../ascii.h"
#include "../bin.h"
#include "../cp1252.h"
#include "../shift_jis.h"
#include "../utf8.h"
#include "../utf16.h"
// ...

typedef struct {
  owl_mem_space * arr;
  owl_wchar_enc enc;
  owl_wchar inv;
  owl_wchar null;
  // basic functions
  owl_byte (* check_wchar)(owl_wchar ch);
  owl_byte (* check_wchar_enc)(owl_byte * src, owl_umax size);
  owl_wchar (* get_wchar)(owl_byte * src, owl_umax size);
  owl_byte * (* write_wchar_enc)(owl_wchar ch, owl_byte * dest, owl_umax size);
  owl_byte (* print_wchar)(owl_wchar ch);
  owl_byte (* print_wchar_enc)(owl_byte * src, owl_umax size);
  // conversion to unicode
  owl_wchar (* wchar_as_unicode)(owl_wchar encoding);
  owl_wchar (* wchar_unicode_as)(owl_wchar unicode);
  // character constants
  owl_wchar * num; // numbers
  owl_wchar * wsp; // whitespaces
  owl_wchar * path; // path
  owl_wchar * letr; // letters
} owl_str;

typedef enum {
  OWL_TYPE_STR = OWL_TYPE_WCHAR + 1,
} owl_type_string_h;

// string function holders
owl_str OWL_STR_FUNCS[OWL_WCHAR_ENC_INVALID] = 
{
  {
    NULL
  },
  {
    NULL, OWL_WCHAR_ENC_ASCII,
    OWL_INV_ASCII,
    OWL_ASCII_NULL,
    owl_check_wchar_ascii,
    owl_check_wchar_enc_ascii,
    owl_get_wchar_ascii,
    owl_write_wchar_enc_ascii,
    owl_print_wchar_ascii,
    owl_print_wchar_enc_ascii,
    owl_wchar_ascii_as_unicode,
    owl_wchar_unicode_as_ascii,
    OWL_ASCII_NUM,
    OWL_ASCII_WSP,
    OWL_ASCII_PATH,
    OWL_ASCII_LETR
  },
  {
    NULL, OWL_WCHAR_ENC_BIN,
    OWL_INV_BIN,
    OWL_BIN_NULL,
    owl_check_wchar_bin,
    owl_check_wchar_enc_bin,
    owl_get_wchar_bin,
    owl_write_wchar_enc_bin,
    owl_print_wchar_bin,
    owl_print_wchar_enc_bin,
    owl_wchar_bin_as_unicode,
    owl_wchar_unicode_as_bin,
    OWL_BIN_NUM,
    OWL_BIN_WSP,
    OWL_BIN_PATH,
    OWL_BIN_LETR
  },
  {
    NULL, OWL_WCHAR_ENC_CP1252,
    OWL_INV_CP1252,
    OWL_CP1252_NULL,
    owl_check_wchar_cp1252,
    owl_check_wchar_enc_cp1252,
    owl_get_wchar_cp1252,
    owl_write_wchar_enc_cp1252,
    owl_print_wchar_cp1252,
    owl_print_wchar_enc_cp1252,
    owl_wchar_cp1252_as_unicode,
    owl_wchar_unicode_as_cp1252,
    OWL_CP1252_NUM,
    OWL_CP1252_WSP,
    OWL_CP1252_PATH,
    OWL_CP1252_LETR
  },
  {
    NULL, OWL_WCHAR_ENC_SHIFT_JIS,
    OWL_INV_SHIFT_JIS,
    OWL_SHIFT_JIS_NULL,
    owl_check_wchar_shift_jis,
    owl_check_wchar_enc_shift_jis,
    owl_get_wchar_shift_jis,
    owl_write_wchar_enc_shift_jis,
    owl_print_wchar_shift_jis,
    owl_print_wchar_enc_shift_jis,
    owl_wchar_shift_jis_as_unicode,
    owl_wchar_unicode_as_shift_jis,
    OWL_SHIFT_JIS_NUM,
    OWL_SHIFT_JIS_WSP,
    OWL_SHIFT_JIS_PATH,
    OWL_SHIFT_JIS_LETR
  },
  {
    NULL, OWL_WCHAR_ENC_UTF8,
    OWL_INV_UNICODE,
    OWL_UNICODE_NULL,
    owl_check_wchar_utf8,
    owl_check_wchar_enc_utf8,
    owl_get_wchar_utf8,
    owl_write_wchar_enc_utf8,
    owl_print_wchar_utf8,
    owl_print_wchar_enc_utf8,
    owl_wchar_utf8_as_unicode,
    owl_wchar_unicode_as_utf8,
    OWL_UNICODE_NUM,
    OWL_UNICODE_WSP,
    OWL_UNICODE_PATH,
    OWL_UNICODE_LETR
  },
  {
    NULL, OWL_WCHAR_ENC_UTF16BE,
    OWL_INV_UNICODE,
    OWL_UNICODE_NULL,
    owl_check_wchar_utf16,
    owl_check_wchar_enc_utf16be,
    owl_get_wchar_utf16be,
    owl_write_wchar_enc_utf16be,
    owl_print_wchar_utf16,
    owl_print_wchar_enc_utf16be,
    owl_wchar_utf16_as_unicode,
    owl_wchar_unicode_as_utf16,
    OWL_UNICODE_NUM,
    OWL_UNICODE_WSP,
    OWL_UNICODE_PATH,
    OWL_UNICODE_LETR
  },
  {
    NULL, OWL_WCHAR_ENC_UTF16LE,
    OWL_INV_UNICODE,
    OWL_UNICODE_NULL,
    owl_check_wchar_utf16,
    owl_check_wchar_enc_utf16le,
    owl_get_wchar_utf16le,
    owl_write_wchar_enc_utf16le,
    owl_print_wchar_utf16,
    owl_print_wchar_enc_utf16le,
    owl_wchar_utf16_as_unicode,
    owl_wchar_unicode_as_utf16,
    OWL_UNICODE_NUM,
    OWL_UNICODE_WSP,
    OWL_UNICODE_PATH,
    OWL_UNICODE_LETR
  },
};
        
// basic functions
owl_bool owl_check_str_pointer(owl_byte * src, owl_umax size);
owl_bool owl_check_str_members(owl_byte * ptr, owl_umax size, owl_wchar_enc enc);
owl_bool owl_check_str_all(owl_str * data, owl_umax size);
owl_str * owl_create_str(owl_byte * data, owl_umax size, owl_wchar_enc enc);
owl_umax owl_free_str(owl_str * str);
owl_umax owl_print_str(owl_byte * src, owl_umax size);
owl_char owl_comp_str(owl_byte * str1, owl_byte * str2);

// specific functions
owl_byte owl_get_num_ch_as_num(owl_str * str, owl_wchar ch);
owl_byte owl_get_num_as_num_ch_pos(owl_byte num);
owl_umax owl_get_str_ch_length(owl_str * str);
owl_bool owl_str_transcode(owl_str * str, owl_wchar_enc enc);
owl_byte * owl_str_ch_at_index(owl_str * str, owl_umax index);
owl_mem_space * owl_decode_str(owl_str * str);
owl_str * owl_encode_wchars(owl_wchar * arr, owl_umax size, owl_wchar_enc enc);
owl_bool owl_reverse_str(owl_str * str);
owl_byte * owl_find_str_chs(owl_str * str, owl_str * find);
owl_bool owl_check_str_pos(owl_str * str, owl_umax pos); // internal use (mostly)
owl_bool owl_insert_str_chs(owl_str * str, owl_umax pos, owl_str * insert);
owl_bool owl_delete_str_chs(owl_str * str, owl_umax pos, owl_umax rm_size);
owl_byte * owl_skip_str_chs(owl_str * str, owl_bool search_until, owl_str * skip);
owl_bool owl_join_strs(owl_str * str1, owl_str * str2);
owl_byte * owl_find_str_ch(owl_str * str1, owl_wchar ch);
owl_str * owl_get_str_until_ch(owl_byte * data, owl_umax size, owl_wchar_enc enc, 
                               owl_wchar ch, owl_bool keep_last_ch);

// reading numbers from strings
// binary, octal, decimal, hex
// signed and float numbers

// get primitive data types from a chenc array
owl_umax owl_check_str_as_oct(owl_str * str, owl_byte * ptr);
owl_umax owl_get_str_as_oct(owl_str * str, owl_byte * ptr);
owl_umax owl_check_str_as_dec(owl_str * str, owl_byte * ptr);
owl_umax owl_get_str_as_dec(owl_str * str, owl_byte * ptr);
owl_umax owl_check_str_as_hex(owl_str * str, owl_byte * ptr);
owl_umax owl_get_str_as_hex(owl_str * str, owl_byte * ptr);
// sign checking stuff
owl_umax owl_check_sign_mult(owl_str * str, owl_byte * ptr);
owl_char owl_get_sign_mult(owl_str * str, owl_byte * ptr);

// the actual functions to use
owl_umax owl_check_str_as_uint(owl_str * str, owl_byte * ptr);
owl_umax owl_get_str_as_uint(owl_str * str, owl_byte * ptr);
owl_umax owl_check_str_as_sint(owl_str * str, owl_byte * ptr);
owl_smax owl_get_str_as_sint(owl_str * str, owl_byte * ptr);
owl_umax owl_check_str_as_float(owl_str * str, owl_byte * ptr);
owl_fmax owl_get_str_as_float(owl_str * str, owl_byte * ptr);

// write primitive data types into a str
owl_byte * owl_write_num_as_str_oct(owl_umax num, owl_str * str, owl_byte * ptr);
owl_byte * owl_write_num_as_str_dec(owl_umax num, owl_str * str, owl_byte * ptr);
owl_byte * owl_write_num_as_str_hex(owl_umax num, owl_str * str, owl_byte * ptr);
owl_byte * owl_write_uint_as_str(owl_umax num, owl_str * str, owl_byte * ptr);
owl_byte * owl_write_sint_as_str(owl_smax num, owl_str * str, owl_byte * ptr);
owl_byte * owl_write_float_as_str(owl_fmax num, owl_str * str, owl_byte * ptr);

// some hash functions
owl_umax owl_calc_str_schar_pol3_hash(owl_str * str);
owl_umax owl_calc_str_schar_pol31_hash(owl_str * str);

#include "string.c"

#endif // string_h
